using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace GameToolkit.UI
{
    public abstract class DataSource : MonoBehaviour, IDataSource
    {
        public enum EBindingType
        {
            Never,
            Always,
            InstanceOnly,
        }

        [SerializeField]
        bool m_HasSourceHandler;

        protected virtual EBindingType BindingType => EBindingType.InstanceOnly;

        System.Action mRefresher;
        IDataSourceHandler[] mRefreshHandlers;
        object mData;
        bool mIsActive;
        bool mWasBinding;

        protected virtual void Awake()
        {
            mRefresher = RefreshData;
            if (m_HasSourceHandler)
                mRefreshHandlers = GetComponents<IDataSourceHandler>();
        }

        protected virtual void OnEnable()
        {
            mIsActive = true;
            //if (mData != null)
            RefreshData();
            var bind = BindingType;
            if (bind == EBindingType.Always)
                mWasBinding = true;
            else if (bind == EBindingType.InstanceOnly)
                mWasBinding = mData != null && !mData.GetType().IsValueType;
            else
                mWasBinding = false;
            if (mWasBinding)
                OnBindEvents();
            
        }

        protected virtual void OnDisable()
        {
            mIsActive = false;
            if(mWasBinding)
            {
                mWasBinding = false;
                OnUnbindEvents();
            }
        }

        public void ApplyUpdate()
        {
            if (mIsActive)
                MainThread.RunOnMainThread(mRefresher, EExecuteEvent.LateUpdate);
        }

        void RefreshData()
        {
            OnRefreshData();
            var len = mRefreshHandlers == null ? 0 : mRefreshHandlers.Length;
            for (int i = 0; i < len; i++)
            {
                mRefreshHandlers[i].OnRefreshData();
            }
        }

        public object GetData()
        {
            return mData;
        }

        public void SetData(object data)
        {
            if (data != mData)
            {
                if (mWasBinding)
                    OnUnbindEvents();
                mData = data;
                var bind = BindingType;
                if (bind == EBindingType.Always)
                    mWasBinding = mIsActive;
                else if (bind == EBindingType.InstanceOnly)
                    mWasBinding = mIsActive && data != null && !data.GetType().IsValueType;
                else
                    mWasBinding = false;
                if (mWasBinding)
                    OnBindEvents();
                ApplyUpdate();
            }
        }

        protected abstract void OnRefreshData();
        protected virtual void OnBindEvents() { }
        protected virtual void OnUnbindEvents() { }

#if UNITY_EDITOR
        protected virtual void OnValidate()
        {
            var handler = GetComponent<IDataSourceHandler>() != null;
            if(handler != m_HasSourceHandler)
            {
                m_HasSourceHandler = handler;
                EditorUtility.SetDirty(this);
            }
        }
#endif

    }
}